using System.Collections.Generic;
using System.IO;
using System.Text;
using External.UIParticle;
using UnityEngine;
using UnityEngine.Profiling;
using Yoozoo.Core.Common;
using Yoozoo.Core.Extensions.CSharp;
using Yoozoo.Mars.Got;

namespace Gameplay.PVE.Effect
{
    public class PveEffectController : MonoBehaviour
    {
        public ParticleSystem[] particleSystems;
       
        public int[] particleSystemFirstFrameEmitCount;
        public Animator[] animators;
        public Animation[] animations;
        public ParticleTimeGetter particleTimeGetter;
        public LineRenderer[] lineRenderer;
        public TrailRenderer[] trailRenderer;

        public UIParticle[] uiParticles;
        
        
        [TextArea(10, 15)]
        public string Tips;

        public List<GameObject> layerChangeBlackList;
        public int originLayer;

        private MeshFilter[] meshFilters;
        public MeshRenderer[] meshRenderers;
        private SpriteRenderer[] spriteRenderers;
        
        private bool isPause = false;
        public bool isActive = false;
        
        [HideInInspector]
        public bool[] particleSystemsBan;
        [HideInInspector]
        public bool[] meshRenderersBan;
        [HideInInspector]
        public bool[] animatorsBan;
        [HideInInspector]
        public bool[] animationsBan;

        public ParticleGrading grading;

        public Renderer[] particleWithFloatUVRenderer;
        public float[] particleWithFloatUVX;
        public float[] particleWithFloatUVY;

        private float[] particleSystemSimulationSpeed;
        private static readonly int MainSpeedU = Shader.PropertyToID("_MainSpeedU");
        private static readonly int MainSpeedV = Shader.PropertyToID("_MainSpeedV");

        public float PlayTime
        {
            get
            {
                if (particleTimeGetter && animations.IsEmpty())
                {
                    return particleTimeGetter.playTime;
                }
                return 5.123f;
            }
        }

        public bool IsLoop
        {
            get
            {
                if (particleTimeGetter)
                {
                    return particleTimeGetter.loop;
                }

                if (particleSystems == null || particleSystems.Length == 0)
                {
                    return true;
                }
                
                return false;
            }
        }
        
        void Awake()
        {
            Init();
        }

        public void SetLayer(int layer)
        {
            if (layerChangeBlackList != null && layerChangeBlackList.Count > 0)
            {
                return;
            }
            gameObject.SetLayerRecursively(layer);
            /*if (layerChangeBlackList != null)
            {
                for (int i = 0; i < layerChangeBlackList.Count; i++)
                {
                    layerChangeBlackList[i].layer = originLayer;
                }
            }*/
        }

        public void OnValidate()
        {
            Tips = string.Empty;
        }
        
        
        public void Init(bool manualInit = false)
        {
#if UNITY_EDITOR
            {
                var stringBuilder = new StringBuilder();
                var renderers = gameObject.GetComponentsInChildren<Renderer>(true);
                for (int i = 0; i < renderers.Length; i++)
                {
                    var renderer = renderers[i];
                    string shaderName = Path.GetFileName(renderer.sharedMaterial?.shader.name ?? "NA");
                    stringBuilder.AppendFormat("{0}({1}): {2} ({3}) - {4}\n", renderer.gameObject.name, shaderName, renderer.sortingLayerName,
                        renderer.sortingOrder, renderer.sharedMaterial?.renderQueue.ToString() ?? "NA");
                }

                Tips = stringBuilder.ToString();
            }
#endif

            if (particleTimeGetter == null || manualInit)
            {
                //先判断有没有空的粒子系统
                if (manualInit)
                {
                    particleSystems = GetComponentsInChildren<ParticleSystem>(true);
                    List<Renderer> particleWithFloatUVRenderer = new List<Renderer>();
                    List<float> particleWithFloatUVX = new List<float>();
                    List<float> particleWithFloatUVY = new List<float>();
                    for (int i = 0; i < particleSystems.Length; i++)
                    {
                        var ps = particleSystems[i];
                        var renderer = ps.GetComponent<Renderer>();
                        if (renderer == null || !renderer.enabled)
                        {
                            bool hasUIParticle = false;
                            //往上找父节点，如果有UIParticle，则不视为空
                            var parent = renderer.transform;
                            while (parent != null)
                            {
                                var uiParticle = parent.GetComponent<UIParticle>();
                                if (uiParticle)
                                {
                                    hasUIParticle = true;
                                    break;
                                }
                                parent = parent.parent;
                            }

                            if (!hasUIParticle)
                            {
                                Debug.LogError(gameObject.name + "下的"+ps.gameObject.name+" 的粒子系统是空的，已经删除");
                                Object.DestroyImmediate(ps);
                            }
                        }
                        else
                        {
                            var material = renderer.sharedMaterial;
                            if (material != null && material.GetFloat("_MainAnimation")== 1)
                            {
                                particleWithFloatUVRenderer.Add(renderer);
                                particleWithFloatUVX.Add(material.GetFloat("_MainSpeedU"));
                                particleWithFloatUVY.Add(material.GetFloat("_MainSpeedV"));
                            }
                        }
                    }

                    this.particleWithFloatUVRenderer = particleWithFloatUVRenderer.ToArray();
                    this.particleWithFloatUVX = particleWithFloatUVX.ToArray();
                    this.particleWithFloatUVY = particleWithFloatUVY.ToArray();
                }
                
                particleTimeGetter = gameObject.GetOrAddComponent<ParticleTimeGetter>();
                particleTimeGetter.GetPlayTime(false);
                particleSystems = GetComponentsInChildren<ParticleSystem>(true);
                particleSystemFirstFrameEmitCount = new int[particleSystems.Length];
                
                for (int i = 0; i < particleSystems.Length; i++)
                {
                    var ps = particleSystems[i];
                    if (ps.main.startDelay.Evaluate(0) > 0)
                    {
                        continue;
                    }

                    if (ps.trails.enabled)
                    {
                        continue;
                    }
                    int count = 0;
                    var burstCount = ps.emission.burstCount;
                    for (int j = 0; j < burstCount; j++)
                    {
                        var burst = ps.emission.GetBurst(j);
                        if (burst.time == 0)
                        {
                            count += (int)burst.count.Evaluate(0);
                        }
                    }
                    count = Mathf.Min(ps.main.maxParticles, count);
                    particleSystemFirstFrameEmitCount[i] = count;
                }
                
                animators = GetComponentsInChildren<Animator>(true);
                animations = GetComponentsInChildren<Animation>(true);
                layerChangeBlackList = new List<GameObject>();
                var renderers = gameObject.GetComponentsInChildren<Renderer>(true);
                for (int i = 0; i < renderers.Length; i++)
                {
                    var renderer = renderers[i];
                    var mat = renderer.sharedMaterial;
                    if (mat != null && mat.shader.name.Contains("HeatOnly"))
                    {
                        layerChangeBlackList.Add(renderer.gameObject);
                    }
                }

                meshRenderers = gameObject.GetComponentsInChildren<MeshRenderer>(true);
                spriteRenderers = gameObject.GetComponentsInChildren<SpriteRenderer>(true);
                meshFilters = gameObject.GetComponentsInChildren<MeshFilter>(true);
                lineRenderer = gameObject.GetComponentsInChildren<LineRenderer>(true);
                trailRenderer = gameObject.GetComponentsInChildren<TrailRenderer>(true);
                uiParticles = gameObject.GetComponentsInChildren<UIParticle>(true);
                
                originLayer = gameObject.layer;
                
                animatorsBan = new bool[animators.Length];
                animationsBan = new bool[animations.Length];
                meshRenderersBan = new bool[meshRenderers.Length];
                particleSystemsBan = new bool[particleSystems.Length];

                grading = GetComponent<ParticleGrading>();
                if (grading)
                {
                    grading.InitData(this);
                }
            }

            particleSystemSimulationSpeed = new float[particleSystems.Length];
            for (int i = 0; i < particleSystems.Length; i++)
            {
                var ps = particleSystems[i];
                if (ps != null)
                {
                    var main = ps.main;
                    var speed = main.simulationSpeed;
                    particleSystemSimulationSpeed[i] = speed;
                }
            }
            isPause = false;
        }

        public void InitGrading()
        {
            grading = GetComponent<ParticleGrading>();
            if (grading)
            {
                grading.InitData(this);
            }
        }
        private int GetLevel(QualityEnum quality)
        {
            int level = 2;
            switch (quality)
            {
                case QualityEnum.Low:
                case QualityEnum.Medium:
                    level = 2;
                    break;
                case QualityEnum.High:
                case QualityEnum.VeryHigh:
                    level = 1;
                    break;
                case QualityEnum.Perfect:
                    level = 0;
                    break;
            }

            return level;
        }

        public void RefreshNodeByLevel(int lv = -1)
        {
            var level = lv;
            if (lv == -1)
            {
                level = GetLevel(QualityManager.Inst.CurrentQuality);
            }
            if (grading)
            {
                ParticleGradingData data = null;
                if (level == 0)
                {
                    data = grading.level0;
                }
                else if (level == 1)
                {
                    data = grading.level1;
                }
                else
                {
                    data = grading.level2;
                }

                for (int i = 0; i < particleSystemsBan.Length; i++)
                {
                    particleSystemsBan[i] = false;
                }

                if (data.disableParticlesIndex != null)
                {
                    var newParticles = new ParticleSystem[particleSystems.Length - data.disableParticlesIndex.Count];
                    var newFirstFrameEmit = new int[newParticles.Length];
                    int disableIndex = 0;
                    int newIndex = 0;
                    for (int i = 0; i < particleSystems.Length; i++)
                    {
                        if (disableIndex < data.disableParticlesIndex.Count &&
                            data.disableParticlesIndex[disableIndex] == i)
                        {
                            disableIndex++;
                            particleSystems[i].Stop(true);
                            Object.Destroy(particleSystems[i].gameObject);
                        }
                        else
                        {
                            if (newIndex >= newParticles.Length)
                            {
                                Debug.LogError(gameObject.name);
                                break;
                            }
                            newParticles[newIndex] = particleSystems[i];
                            newFirstFrameEmit[newIndex] = 0;
                            if (particleSystemFirstFrameEmitCount.Length > i)
                            {
                                newFirstFrameEmit[newIndex] = particleSystemFirstFrameEmitCount[i];
                            }
                            newIndex++;
                        }
                    }
                    particleSystems = newParticles;
                    particleSystemFirstFrameEmitCount = newFirstFrameEmit;
                }
                
                Object.Destroy(grading);
            }
        }
        
        public void GetData()
        {
            Init(true);
        }

        public void Pause()
        {
            if (isPause)
            {
                return;
            }
            isPause = true;
            if (particleSystems != null)
            {
                for (int i = 0; i < particleSystems.Length; i++)
                {
                    if (particleSystems[i])
                    {
                        particleSystems[i].Pause();
                    }
                }

                if (this.particleWithFloatUVRenderer != null)
                {
                    for (int i = 0; i < this.particleWithFloatUVRenderer.Length; i++)
                    {
                        var renderer = particleWithFloatUVRenderer[i];
                        if (renderer != null)
                        {
                            var material = renderer.sharedMaterial;
                            if (material != null)
                            {
                                material.SetFloat(MainSpeedU, 0);
                                material.SetFloat(MainSpeedV, 0);
                            }
                        }
                    }
                }
            }

            if (animators != null)
            {
                for (int i = 0; i < animators.Length; i++)
                {
                    if (animators[i])
                    {
                        animators[i].speed = 0;
                    }
                }
            }

            if (animations != null)
            {
                foreach (var animation1 in animations)
                {
                    foreach (AnimationState animationState in animation1)
                    {
                        animationState.speed = 0;
                    }
                }
            }
        }

        public void Resume()
        {
            if (!isPause)
            {
                return;
            }
            isPause = false;
            if (particleSystems != null)
            {
                for (int i = 0; i < particleSystems.Length; i++)
                {
                    if (particleSystems[i])
                    {
                        particleSystems[i].Play();
                    }
                }
                if (this.particleWithFloatUVRenderer != null)
                {
                    for (int i = 0; i < this.particleWithFloatUVRenderer.Length; i++)
                    {
                        var renderer = particleWithFloatUVRenderer[i];
                        if (renderer)
                        {
                            if (particleWithFloatUVX != null && particleWithFloatUVX.Length > i &&
                                particleWithFloatUVY != null && particleWithFloatUVY.Length > i)
                            {
                                var material = renderer.sharedMaterial;
                                if (material)
                                {
                                    material.SetFloat(MainSpeedU,this.particleWithFloatUVX[i]);
                                    material.SetFloat(MainSpeedV,this.particleWithFloatUVY[i]);  
                                }
                            }
                        }
                    }
                }
            }
            
            if (animators != null)
            {
                for (int i = 0; i < animators.Length; i++)
                {
                    if (animators[i])
                    {
                        animators[i].speed = 1;
                    }
                }
            }

            if (animations != null)
            {
                foreach (var animation1 in animations)
                {
                    if (animation1)
                    {
                        foreach (AnimationState animationState in animation1)
                        {
                            animationState.speed = 1;
                        }
                    }
                }
            }
        }

        public void SetSpeed(float speed)
        {
            if (animators != null)
            {
                for (int i = 0; i < animators.Length; i++)
                {
                    if (animators[i])
                    {
                        animators[i].speed = speed;
                    }
                }
            }

            if (animations != null)
            {
                foreach (var animation1 in animations)
                {
                    foreach (AnimationState animationState in animation1)
                    {
                        animationState.speed = 1;
                    }
                }
            }

            if (particleSystems != null)
            {
                for (int i = 0; i < particleSystems.Length; i++)
                {
                    var ps = particleSystems[i];
                    if (ps != null)
                    {
                        var main = ps.main;
                        if (particleSystemSimulationSpeed != null && particleSystemSimulationSpeed.Length > i)
                        {
                            main.simulationSpeed = speed * particleSystemSimulationSpeed[i];
                        }
                        else
                        {
                            main.simulationSpeed = speed;
                        }
                    }
                }
            }
        }

        public void SetActive(bool active)
        {
            this.isActive = active;
            //Profiler.BeginSample("PveEffectController.SetActive");
            //Profiler.BeginSample("PveEffectController.SetActive.Animator");
            if (animators != null)
            {
                for (int i = 0; i < animators.Length; i++)
                {
                    var animator = animators[i];
                    if (animator != null)
                    {
                        animator.enabled = active;
                        if (active)
                        { 
                            if (animator.gameObject.activeInHierarchy)
                            {
                                for (int j = 0; j < animator.layerCount; j++)
                                {
                                    var info = animator.GetCurrentAnimatorStateInfo(j);
                                    animator.Play(info.fullPathHash,j,0);
                                }
                            }
                            else
                            {
                                //Debug.LogError(name+"anaimatorController 所在的go inactive  "+animator.gameObject.name);
                            }
                          
                        }
                    }
                    else
                    {
                        //Debug.LogError(name+"动画为空");
                    }
                }
            }
            //Profiler.EndSample();

            //Profiler.BeginSample("PveEffectController.SetActive.Animation");
            if (animations != null)
            {
                for (int i = 0; i < animations.Length; i++)
                {
                    if (animations[i] != null)
                    {
                        animations[i].enabled = active;
                        if (active)
                        {
                            if (animations[i].gameObject.activeInHierarchy)
                            {
                                animations[i].Play();
                            }
                            else
                            {
                                //Debug.LogError(name+"动画所在go inactive  "+animations[i].gameObject.name);
                            }
                            
                        }
                    }
                    else
                    {
                        //Debug.LogError(name+"动画为空");
                    }
                }
            }
            //Profiler.EndSample();

            //Profiler.BeginSample("PveEffectController.SetActive.Particle");
            if (particleSystems != null)
            {
                for (int i = 0; i < particleSystems.Length; i++)
                {
                    var ps = particleSystems[i];
                    if (ps != null)
                    {
                        if (!active)
                        {
                            ps.Stop();
                            ps.Clear();
                        }
                        else
                        {
                            ps.Play();
                            //刚播放就必须瞬间发射的粒子，解决下一帧粒子才出现的问题
                            if (particleSystemFirstFrameEmitCount != null && particleSystemFirstFrameEmitCount.Length > i)
                            {
                                ps.Emit(particleSystemFirstFrameEmitCount[i]);
                            }
                           
                        }
                    }
                    else
                    {
                        //Debug.LogError(name+"粒子为空");
                    }
                }
                if (particleWithFloatUVRenderer != null)
                {
                    for (int i = 0; i < particleWithFloatUVRenderer.Length; i++)
                    {
                        var renderer = particleWithFloatUVRenderer[i];
                        if (renderer != null)
                        {
                            var material = renderer.sharedMaterial;
                            if (material != null && particleWithFloatUVX != null && particleWithFloatUVX.Length > i && particleWithFloatUVY != null && particleWithFloatUVY.Length > i)
                            {
                                material.SetFloat(MainSpeedU,particleWithFloatUVX[i]);
                                material.SetFloat(MainSpeedV,particleWithFloatUVY[i]);
                            }
                        }
                    }
                }
            }
            //Profiler.EndSample();

            //Profiler.BeginSample("PveEffectController.SetActive.MeshFilter");
            if (meshFilters != null)
            {
                for (int i = 0; i < meshFilters.Length; i++)
                {
                    var meshFilter = meshFilters[i];
                    if (meshFilter != null)
                    {
                        meshFilter.SetActive(active);
                    }
                }
            }
            //Profiler.EndSample();
            
            //Profiler.BeginSample("PveEffectController.SetActive.MeshRenderer");
            if (meshRenderers != null)
            {
                for (int i = 0; i < meshRenderers.Length; i++)
                {
                    var meshRenderer = meshRenderers[i];
                    if (meshRenderer != null)
                    {
                        meshRenderer.enabled = active;
                    }
                }
            }
            //Profiler.EndSample();

            //Profiler.BeginSample("PveEffectController.SetActive.SpriteRender");
            if (spriteRenderers != null)
            {
                for (int i = 0; i < spriteRenderers.Length; i++)
                {
                    var spriteRenderer = spriteRenderers[i];
                    if (spriteRenderer != null)
                    {
                        spriteRenderer.enabled = active;
                    }
                }
            }
            //Profiler.EndSample();

            //Profiler.BeginSample("PveEffectController.SetActive.LineRender");
            if (lineRenderer != null)
            {
                for (int i = 0; i < lineRenderer.Length; i++)
                {
                    var lineRenderer = this.lineRenderer[i];
                    if (lineRenderer != null)
                    {
                        lineRenderer.enabled = active;
                    }
                }
            }
            //Profiler.EndSample();
            
            //Profiler.BeginSample("PveEffectController.SetActive.Trail");
            SetTrailEnabled(active);
            //Profiler.EndSample();

            if (uiParticles != null)
            {
                for (int i = 0; i < uiParticles.Length; i++)
                {
                    var uiParticle = uiParticles[i];
                    if (uiParticle != null)
                    {
                        uiParticle.enabled = active;
                    }
                }
                
            }
            //Profiler.EndSample();
        }

        public void SetLineRendererLength(float length)
        {
            if (lineRenderer != null)
            {
                for (int i = 0; i < lineRenderer.Length; i++)
                {
                    var index = lineRenderer[i].positionCount - 1;
                    //var endPosition = lineRenderer[i].GetPosition(index);
                    lineRenderer[i].SetPosition(index,new Vector3(0,0,length));
                }
            }
        }

        public void SetTrailEnabled(bool enabled,bool clearPath = true)
        {
            if (trailRenderer != null)
            {
                for (int i = 0; i < trailRenderer.Length; i++)
                {
                    var trailRenderer = this.trailRenderer[i];
                    if (trailRenderer != null)
                    {
                        if (!enabled && clearPath)
                        {
                            trailRenderer.Clear();
                        }
                        trailRenderer.enabled = enabled;
                    }
                }
            }
        }

        public void SetParticleCustomDataVector(int index,float value)
        {
            for (int i = 0; i < particleSystems.Length; i++)
            {
                var particle = particleSystems[i];
                if (particle != null)
                {
                    if (particle.customData.enabled)
                    {
                        var vector = particle.customData.GetVector(ParticleSystemCustomData.Custom1,index);
                        vector.mode = ParticleSystemCurveMode.Constant;
                        vector.constant = value;
                        particle.customData.SetVector(ParticleSystemCustomData.Custom1,index,vector);
                    }
                }
            }
        }
    }
}
